package com.donnees.mysql;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.List;

import javax.swing.JOptionPane;

import com.metier.logique.ConfigurationProjet;
import com.metier.logique.MSG;
import com.metier.persistance.Parcours;


/**
 * @name ParcoursMysqlDAO
 * @description Étend la classe AbstractDAO<Person>.
 * 				Cette classe représente toutes les méthodes que peut effectuer la table Parcours dans la base de données MySQL
 * @method inheritage - find - Méthode générique traitant l'objet MSG reçu en paramètre et créant la requête SQL en fonction du MSG.
 * @method inheritage - findAll - Méthode récupérant tous les résultats sans filtrage.
 * @method inheritage - delete - Méthode générique traitant l'objet MSG reçu en paramètre et créant la requête SQL en fonction du MSG.
 * @method inheritage - update - Méthode générique traitant l'objet MSG reçu en paramètre et créant la requête SQL en fonction du MSG.
 * @method inheritage - insert - Méthode générique traitant l'objet MSG reçu en paramètre et créant la requête SQL en fonction du MSG.
 * @method inheritage - getNombreLignesByResulSet - Retourne le nombre de lignes d'un ResultSet.
 * @method inheritage - generateParameters - Modifie la requetePreparee courante en lui rajoutant des attributs.
 * 
 * @author Ambroise
 * @since 07/03/2012
 * 
 */
public class ParcoursMysqlDAO extends MySqlDAO<Parcours>{

	/**
	 * @name find
	 * @description Méthode générique traitant l'objet MSG reçu en paramètre et créant la requête SQL en fonction du MSG.
	 * 
	 * @param {@link MSG} oMSG<br />
	 * <b>select</b> - String - Obligatoire - Doit contenir tous les champs à récupérer séparés par des virgules ainsi que les éventuels count et leur alias. <br />
	 * 		  	- Ex: "SELECT ID_PERSONNE, NOM, PRENOM, COUNT(ID_PERSONNE) AS COUNT_TOTAL"<br />
	 * 
	 * <b>from</b> - String - Obligatoire - Doit contenir la totalité de la chaîne FROM de la requête SQL. (Les tables ainsi que les jointures entre les tables.)<br />
	 * 			- Ex: "FROM personne, types" | "FROM personne LEFT OUTER JOIN types ON personne.TYPE_PERSONNE = types.ID_TYPES"<br />
	 * 
	 * <b>parametresInconnus</b> - MSG - Optionnel - Doit contenir autant de valeurs qu'il y a de paramètres dans la requête préparée.<br />
	 * 			- Ex: 	<br /><br /><code>
	  					Personne oPersonne = new Personne();
						
						Object[] parametresInconnus = new Object[2];
						parametresInconnus[0] = 1;
						parametresInconnus[1] = 14;
						
						MSG oMSG3 = new MSG();
						oMSG3.setData("parametresInconnus", parametresInconnus);
						oMSG3.setData("select", "SELECT ID_PERSONNE, NOM, PRENOM");
						oMSG3.setData("from", "FROM personne");
						oMSG3.setData("where", "WHERE ID_PERSONNE BETWEEN ? AND ?");
						oMSG3.setData("orderBy", "ORDER BY NOM, PRENOM, ID_PERSONNE");
						
						MSG result = oPersonne.get(oMSG3);
						while(result.getData("donnees").next()){
							System.out.println("ID:" + result.getInt("ID_PERSONNE") + ", Nom: " +result.getString("NOM") + ", Prénom: " + result.getString("PRENOM"));
						}
	 * </code><br /><br />
	 * <b>where</b> - String - Optionnel - Doit contenir la clause WHERE de la requête SQL. (Pour limiter les résultats, réaliser des jointures, etc...)<br />
	 * 			- Ex: "WHERE ID_PERSONNE = 5" | WHERE NOM LIKE '%bouh%'<br />
	 * 
	 * 		Utiliser les requêtes préparées:	- Ex: "WHERE ID_PERSONNE = ?" | WHERE ID_PERSONNE IN (?) | WHERE NOM LIKE '?'<br />
	 * 
	 * <b>groupBy</b> - String - Optionnel - Doit contenir la clause GROUP BY de la requête SQL. (En général utilisé lors d'un COUNT)<br />
	 * 			- Ex: "GROUP BY NOM" | "GROUP BY NOM, PRENOM"<br />
	 * 
	 * <b>orderBy</b> - String - Optionnel - Doit contenir la clause ORDER BY de la requête SQL. (select ASC/DESC concaténés entres eux)<br />
	 * 		  	- Ex: "ORDER BY NOM, PRENOM, DATE_NAISSANCE DESC"<br />
 	 *			
	 * @return {@link MSG} MSG contenant toutes les informations concernant les résultats.<br />
	 * 			oMSG.getData("donnees"); -> Contient les résultats de la requête SQL.
	 * 			oMSG.getData("typeDonnees"); -> Contient le type de résultat contenu par "donnees", Liste, Objet spécifique à la classe ou bien "null" si la requête n'a retourné aucun résultat.
	 */
	@Override
	public MSG find(MSG oMSG) {
		this.sql = "";
		
		if(oMSG.getData("select") != null && oMSG.getData("from") != null){
			// Création de la requête SQL.
			this.sql +=  oMSG.getData("select") + " " + oMSG.getData("from") + " ";
			
			if(oMSG.getData("where") != null){
				this.sql +=  oMSG.getData("where") + " ";
			}
			
			if(oMSG.getData("groupBy") != null){
				this.sql +=  oMSG.getData("groupBy") + " ";				
			}
			
			if(oMSG.getData("orderBy") != null){
				this.sql +=  oMSG.getData("orderBy") + " ";				
			}
			
			this.sql += ";";
			
			
			try{
				Connection oConnection = MySqlDAOFactory.getConnection();
			
				this.requetePreparee = oConnection.prepareStatement(
					this.sql,
					Statement.RETURN_GENERATED_KEYS// On souhaite récupérer les clés, que ce soit le dernier ID inséré ou bien le nombre de lignes modifiées/supprimées.
				);
				
				// Configuration des paramètres d'une éventuelle requête paramétrée.
				if(oMSG.getData("parametresInconnus") != null){
					Object[] parametresInconnus = (Object[]) oMSG.getData("parametresInconnus");
					
					// On appelle la méthode de génération des paramètres.
					generateParameters(parametresInconnus);
				}
				
				// On affiche la requête si le projet est en mode debuguage.
				if(ConfigurationProjet.MODE_DEBUG){
					System.out.println(this.requetePreparee);
				}
				
				oMSG.setData("params", this.requetePreparee);
				
				// On exécute la requête.
				this.resultats = (ResultSet) requetePreparee.executeQuery();
				
				// S'il y a plusieurs résultats on les renvoi sous forme de liste.
				if(getNombreLignesByResulSet(this.resultats) > 1){
					List<Parcours> listeObjets = new ArrayList<Parcours>();
					while(this.resultats.next()){
						Parcours objetTemp = new Parcours();
						objetTemp.setIdParcours(this.resultats.getBigDecimal("ID_PARCOURS"));
						objetTemp.setNom(this.resultats.getString("NOM"));
						objetTemp.setDescriptif(this.resultats.getString("DESCRIPTIF"));
						objetTemp.setDateCreation(this.resultats.getDate("DATE_CREATION"));
						objetTemp.setDateModification(this.resultats.getDate("DATE_MODIFICATION"));
						
						// On stocke l'objet temporaire dans la liste.
						listeObjets.add(objetTemp);
					}
					// On met la liste dans le MSG de retour.
					oMSG.setData("donnees", listeObjets);
					oMSG.setData("typeDonnees", "list");
					
				}else if(getNombreLignesByResulSet(this.resultats) == 1){
					// Sinon, s'il y a qu'un seul résultat, on crée directement un objet.
					this.resultats.first();
					Parcours objetTemp = new Parcours();
					objetTemp.setIdParcours(this.resultats.getBigDecimal("ID_PARCOURS"));
					objetTemp.setNom(this.resultats.getString("NOM"));
					objetTemp.setDescriptif(this.resultats.getString("DESCRIPTIF"));
					objetTemp.setDateCreation(this.resultats.getDate("DATE_CREATION"));
					objetTemp.setDateModification(this.resultats.getDate("DATE_MODIFICATION"));
					
					// On met l'objet dans le MSG de retour.
					oMSG.setData("donnees", objetTemp);
					oMSG.setData("typeDonnees", "object");
					
				}else{
					// On dit qu'il y a pas de résultat dans le MSG de retour.
					oMSG.setData("donnees", new Parcours());
					oMSG.setData("typeDonnees", "null");
				}
				
			}catch (Exception e) {
				JOptionPane.showMessageDialog(null, "Erreur inconnue lors de l'exécution de la méthode "+this.getClass().getSimpleName()+".find().\n\n<html><body><u>Message d'erreur</u>:<body></html>\n" + e.getMessage(), "Erreur", JOptionPane.ERROR_MESSAGE);
			}
		}else{
			JOptionPane.showMessageDialog(null, "Erreur lors de l'exécution de la méthode "+this.getClass().getSimpleName()+".find(). Les arguments 'select' et 'from' sont obligatoires.", "Arguments manquants", JOptionPane.ERROR_MESSAGE);
		}
				
		return oMSG;
	}

	/**
	 * @name findAll
	 * @description Méthode générique traitant l'objet MSG reçu en paramètre et créant la requête SQL en fonction du MSG.
	 * 
	 * @param {@link MSG} oMSG<br />
	 * 
	 * <b>from</b> - String - Obligatoire - Doit contenir la totalité de la chaîne FROM de la requête SQL. (Les tables ainsi que les jointures entre les tables.)<br />
	 * 			- Ex: "FROM personne, types" | "FROM personne LEFT OUTER JOIN types ON personne.TYPE_PERSONNE = types.ID_TYPES"<br />
	 * 
	 * <b>parametresInconnus</b> - MSG - Optionnel - Doit contenir autant de valeurs qu'il y a de paramètres dans la requête préparée.<br />
	 * 			- Ex: 	<br /><br /><code>
	  					Personne oPersonne = new Personne();
						
						MSG oMSG3 = new MSG();
						oMSG3.setData("from", "personne");
						
						MSG result = oPersonne.get(oMSG3);
						while(result.getData("donnees").next()){
							System.out.println("ID:" + result.getInt("ID_PERSONNE") + ", Nom: " +result.getString("NOM") + ", Prénom: " + result.getString("PRENOM"));
						}
	 * </code>
 	 *			
	 * @return {@link MSG} MSG contenant toutes les informations concernant les résultats.<br />
	 * 			oMSG.getData("donnees"); -> Contient les résultats de la requête SQL.
	 * 			oMSG.getData("typeDonnees"); -> Contient le type de résultat contenu par "donnees", Liste, Objet spécifique à la classe ou bien "null" si la requête n'a retourné aucun résultat.
	 */
	@Override
	public MSG findAll(MSG oMSG) {
		this.sql = "SELECT *";
		
		if(oMSG.getData("from") != null){
			// Création de la requête SQL.
			this.sql +=  " " + oMSG.getData("from") + ";";			
			
			try{
				Connection oConnection = MySqlDAOFactory.getConnection();
			
				this.requetePreparee = oConnection.prepareStatement(
					this.sql,
					Statement.RETURN_GENERATED_KEYS// On souhaite récupérer les clés, que ce soit le dernier ID inséré ou bien le nombre de lignes modifiées/supprimées.
				);
				
				// Configuration des paramètres d'une éventuelle requête paramétrée.
				if(oMSG.getData("parametresInconnus") != null){
					Object[] parametresInconnus = (Object[]) oMSG.getData("parametresInconnus");
					
					// On appelle la méthode de génération des paramètres.
					generateParameters(parametresInconnus);
				}
				
				// On affiche la requête si le projet est en mode debuguage.
				if(ConfigurationProjet.MODE_DEBUG){
					System.out.println(this.requetePreparee);
				}
				
				oMSG.setData("params", this.requetePreparee);
				
				// On exécute la requête.
				this.resultats = (ResultSet) requetePreparee.executeQuery();
				
				// S'il y a plusieurs résultats on les renvoi sous forme de liste.
				if(getNombreLignesByResulSet(this.resultats) > 1){
					List<Parcours> listeObjets = new ArrayList<Parcours>();
					while(this.resultats.next()){
						Parcours objetTemp = new Parcours();
						objetTemp.setIdParcours(this.resultats.getBigDecimal("ID_PARCOURS"));
						objetTemp.setNom(this.resultats.getString("NOM"));
						objetTemp.setDescriptif(this.resultats.getString("DESCRIPTIF"));
						objetTemp.setDateCreation(this.resultats.getDate("DATE_CREATION"));
						objetTemp.setDateModification(this.resultats.getDate("DATE_MODIFICATION"));
						
						// On stocke l'objet temporaire dans la liste.
						listeObjets.add(objetTemp);
					}
					// On met la liste dans le MSG de retour.
					oMSG.setData("donnees", listeObjets);
					oMSG.setData("typeDonnees", "list");
					
				}else if(getNombreLignesByResulSet(this.resultats) == 1){
					// Sinon, s'il y a qu'un seul résultat, on crée directement un objet.
					this.resultats.first();
					Parcours objetTemp = new Parcours();
					objetTemp.setIdParcours(this.resultats.getBigDecimal("ID_PARCOURS"));
					objetTemp.setNom(this.resultats.getString("NOM"));
					objetTemp.setDescriptif(this.resultats.getString("DESCRIPTIF"));
					objetTemp.setDateCreation(this.resultats.getDate("DATE_CREATION"));
					objetTemp.setDateModification(this.resultats.getDate("DATE_MODIFICATION"));
					
					// On met l'objet dans le MSG de retour.
					oMSG.setData("donnees", objetTemp);
					oMSG.setData("typeDonnees", "object");
					
				}else{
					// On dit qu'il y a pas de résultat dans le MSG de retour.
					oMSG.setData("donnees", new Parcours());
					oMSG.setData("typeDonnees", "null");
				}
				
			}catch (Exception e) {
				JOptionPane.showMessageDialog(null, "Erreur inconnue lors de l'exécution de la méthode "+this.getClass().getSimpleName()+".find().\n\n<html><body><u>Message d'erreur</u>:<body></html>\n" + e.getMessage(), "Erreur", JOptionPane.ERROR_MESSAGE);
			}
		}else{
			JOptionPane.showMessageDialog(null, "Erreur lors de l'exécution de la méthode "+this.getClass().getSimpleName()+".find(). Les arguments 'select' et 'from' sont obligatoires.", "Arguments manquants", JOptionPane.ERROR_MESSAGE);
		}
				
		return oMSG;
	}
}
